//
// contrib.c
// stuff written by other folks, seen on blogs, etc.
//
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "always_assert.h"

//
// wonderful utf-8 counting trickery
// by colin percival
//
// http://www.daemonology.net/blog/2008-06-05-faster-utf8-strlen.html
//

// 展开为： 0x01010101_01010101
#define ONEMASK ((size_t)(-1) / 0xFF)
// NOTE: GCC 会尽量优化表达式中的常量，因此没必要为性能加入宏，除非可提高可读性。
// 展开为： 0x80808080_80808080
// #define TOP1MASK (ONEMASK * 0x80)

// 取 utf8 字符串( \0 结尾）的字符数。
// 分三段处理：中段对齐到 8bytes(64bit) 每次处理 8bytes ，前后段都不足 8bytes 逐字节处理。
size_t
potion_cp_strlen_utf8(const char * _s)
{
  const char * s;
  size_t count = 0; // 字节 0b10xxxxxx 的数量
  size_t u;
  unsigned char b;

  for (s = _s; (uintptr_t)(s) & (sizeof(size_t) - 1); s++) {
    b = *s;
    if (b == '\0') goto done;
    count += (b >> 7) & ((~b) >> 6);
  }

  // TODO hsq 使用 SIMD 等指令，或更高级的指令集？
  for (; ; s += sizeof(size_t)) {
    #ifdef __builtin_prefetch
      // tcc 未定义 __builtin_prefetch ？
      __builtin_prefetch(&s[256], 0, 0); // 0, 0 分别表示 读 和 无是兼具不行
    #endif
    u = *(size_t *)(s);
    // 每个字节，只在为 0x00 时，if 条件非 0 ，因此可判断到了字符串末尾。
    //  ((char - 0x01) & ~char & 0x80)
    if ((u - ONEMASK) & (~u) & (ONEMASK * 0x80)) break;
    // 每个字节，若为 0b10xxxxxx 形式，则变为 0x01 。
    u = ((u & (ONEMASK * 0x80)) >> 7) & ((~u) >> 6);
    // 最高字节是所有字节的累加，右移为最低字节则为这段的 0b10xxxxxx 数量。
    count += (u * ONEMASK) >> ((sizeof(size_t) - 1) * 8);
  }

  for (; ; s++) {
    b = *s;
    if (b == '\0') break;
    count += (b >> 7) & ((~b) >> 6);
  }
  done:
  return ((s - _s) - count);
}

#ifdef __MINGW32__
  #include <windows.h>
  #include <sys/unistd.h>

  void *potion_mmap(size_t length, const char exec)
  {
    void *mem = VirtualAlloc(NULL, length, MEM_COMMIT,
      exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE);
    if (mem == NULL)
      FAIL_MSG(stderr, "potion_mmap failed");
    assert(mem != NULL);
    return mem;
  }

  int potion_munmap(void *mem, size_t len)
  {
    return VirtualFree(mem, len, MEM_DECOMMIT) != 0 ? 0 : -1;
  }

#else
  #include <sys/mman.h>

  // 返回映射内存可读写、可能为 NULL。
  void *potion_mmap(size_t length)
  {
    void *mem = mmap(NULL, length, PROT_READ|PROT_WRITE,
      (MAP_PRIVATE|MAP_ANON), -1, 0);
    // 调用处都没检查 NULL 。
    // if (mem == MAP_FAILED) return NULL;
    assert(mem != MAP_FAILED);
    return mem;
  }

  // 转换映射内存的保护模式： read & exec 或 read & write ； exec 是否可执行。
  void *potion_mprotect(void *addr, size_t length, const char exec)
  {
    int prot = (exec ? PROT_EXEC : PROT_WRITE) | PROT_READ;
    int ret  = mprotect(addr, length, prot);
    // 调用处都没检查 NULL 。
    // if (ret != 0) return NULL;
    assert(ret == 0);
    return addr;
  }


  // 释放映射内存
  int potion_munmap(void *mem, size_t len)
  {
    return munmap(mem, len);
  }

#endif
